package br.com.winesys.geta.crud;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import br.com.winesys.geta.base.ExceptionMessage;
import br.com.winesys.geta.databinding.component.listeners.SelectionListener;
import br.com.winesys.geta.databinding.component.table.TableModel;
import br.com.winesys.geta.databinding.component.table.TableViewer;
import br.com.winesys.geta.dialog.BaseDialog;
import br.com.winesys.geta.dialog.ObjectActionDialog;
import br.com.winesys.geta.editor.Editor;

public abstract class CadastroPopup<Entity> extends BaseDialog implements SelectionListener<Entity> {

	protected Action newAction;
    protected Action editAction;
    protected Action deleteAction;
    protected Action refreshAction;
    protected TableViewer<Entity> table;
    protected Entity selected;

    public CadastroPopup(Window owner, String title, Dimension size) {
        super(owner, title, size);
    }

    @Override
    protected void createActions() {
        this.newAction = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                CadastroPopup.this.doNew();
            }
        };
        this.newAction.setEnabled(canInsert());
        this.newAction.putValue(Action.NAME, "Novo");
        this.newAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_N);
        this.newAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke('N', InputEvent.CTRL_MASK));
        this.newAction.putValue(Action.LARGE_ICON_KEY, new ImageIcon(CadastroPopup.class.getResource("/images/new.png")));

        this.editAction = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                CadastroPopup.this.doEdit(CadastroPopup.this.selected);
            }
        };
        this.editAction.setEnabled(false);
        this.editAction.putValue(Action.NAME, "Editar");
        this.editAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_E);
        this.editAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke('E', InputEvent.CTRL_MASK));
        this.editAction.putValue(Action.LARGE_ICON_KEY, new ImageIcon(CadastroPopup.class.getResource("/images/edit.png")));

        this.deleteAction = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                CadastroPopup.this.doDelete(CadastroPopup.this.selected);
            }
        };
        this.deleteAction.setEnabled(false);
        this.deleteAction.putValue(Action.NAME, "Excluir");
        this.deleteAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_X);
        this.deleteAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
        this.deleteAction.putValue(Action.LARGE_ICON_KEY, new ImageIcon(CadastroPopup.class.getResource("/images/delete.png")));

        this.refreshAction = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                CadastroPopup.this.doRefresh();
            }
        };
        this.refreshAction.setEnabled(true);
        this.refreshAction.putValue(Action.NAME, "Atualizar");
        this.refreshAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
        this.refreshAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("F5"));
        this.refreshAction.putValue(Action.LARGE_ICON_KEY, new ImageIcon(CadastroPopup.class.getResource("/images/refresh.png")));
    }

    @Override
    protected JComponent createComponent() {
        this.table = new TableViewer<Entity>() {

            @Override
            protected Editor<?> createFilter() {
                return CadastroPopup.this.createFilter();
            }

            @Override
            protected TableModel<Entity> createTableModel() {
                return CadastroPopup.this.createTableModel();
            }
        };
        this.table.addSelectionListener(this);
        return this.table;
    }

    @Override
    protected JMenuBar createMenuBar() {
        return null;
    }

    @Override
    protected JToolBar createToolBar() {
        JToolBar toolBar = new JToolBar(SwingConstants.HORIZONTAL);
        toolBar.setFloatable(false);
        toolBar.add(this.newAction);
        toolBar.add(this.editAction);
        toolBar.add(this.deleteAction);
        toolBar.addSeparator();
        toolBar.add(this.refreshAction);
        toolBar.addSeparator();
        return toolBar;
    }

    @Override
    protected JPanel createStatus() {
        return null;
    }

    @Override
    public void run() {
        this.initGUI();
        this.doRefresh();
        this.dialog.setVisible(true);
    }

    @Override
    public void itemSelected(Entity object) {
        this.selected = object;
        this.newAction.setEnabled(canInsert());
        this.editAction.setEnabled(this.selected != null && canEdit());
        this.deleteAction.setEnabled(this.selected != null && canDelete());
    }

    protected boolean canInsert() {
        return true;
    }

    protected boolean canEdit() {
        return true;
    }

    protected boolean canDelete() {
        return true;
    }

    protected void doDelete(Entity object) {
        if (JOptionPane.showConfirmDialog(this.dialog, "Tem certeza que deseja excluir o item?", "Excluir", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
            try {
                this.delete(object);
            } catch (Exception ex) {
                Toolkit.getDefaultToolkit().beep();
                JOptionPane.showMessageDialog(this.dialog, "Erro ao excluir o item selecionado.\n" + ExceptionMessage.getMessage(ex), "Erro", JOptionPane.ERROR_MESSAGE);
            }
            this.doRefresh();
        }
    }

    protected void doEdit(Entity object) {
        final Editor<Entity> editor = this.createObjectEditor(CadastroAction.EDIT);
        ObjectActionDialog<Entity> editorDialog = new ObjectActionDialog<Entity>(this.dialog, "Novo") {

            @Override
            protected Editor<Entity> createObjectEditor() {
                return editor;
            }

			@Override
			protected Entity newInstance() {
				return CadastroPopup.this.createNewObject();
			}

			@Override
			protected boolean execute(Entity objectAction) {
                CadastroPopup.this.update(objectAction);
                return true;
			}
        };
        editorDialog.run(object);
        doRefresh();
    }

    protected void doNew() {
        Entity object = this.createNewObject();
        final Editor<Entity> editor = this.createObjectEditor(CadastroAction.CREATE);
        ObjectActionDialog<Entity>  editorDialog = new ObjectActionDialog<Entity> (this.dialog, "Editar") {

            @Override
            protected Editor<Entity> createObjectEditor() {
                return editor;
            }
            
            @Override
			protected Entity newInstance() {
				return CadastroPopup.this.createNewObject();
			}

			@Override
			protected boolean execute(Entity objectAction) {
                CadastroPopup.this.insert(objectAction);
                return true;
			}
            
        };
        editorDialog.run(object);
        doRefresh();
    }

    protected void doRefresh() {
        try {
            this.list(this.table.getFilterProperties());
        } catch (Exception ex) {
            Toolkit.getDefaultToolkit().beep();
            JOptionPane.showMessageDialog(this.dialog, ExceptionMessage.getMessage("Erro ao recuperar os items cadastrados.", ex), "Erro", JOptionPane.ERROR_MESSAGE);
        }
    }

    protected abstract void delete(Entity obj);

    protected abstract void insert(Entity obj);

    protected abstract void update(Entity obj);

    protected abstract void list(Map<String, Object> params);

    protected abstract Entity createNewObject();

    protected abstract Editor<Entity> createObjectEditor(CadastroAction action);

    protected abstract Editor<?> createFilter();

    protected abstract TableModel<Entity> createTableModel();
}
